//package com.ccb.sc.common.bind.aspect;
//
//import com.google.common.collect.ImmutableList;
//import com.ccb.sc.common.bind.annotation.Limit;
////psl import com.ccb.sc.common.bind.exception.BizException;
//import com.ccb.sc.common.code.BizCodeFace;
//import com.ccb.sc.common.code.ErrorCode;
//import com.ccb.sc.common.constant.CommonRedisKey;
//import com.ccb.sc.common.modules.common.service.IRedisService;
//import com.ccb.sc.common.util.HttpServletRequestUtil;
//import com.ccb.sc.common.util.IpUtil;
//import org.apache.commons.lang3.StringUtils;
//import org.aspectj.lang.ProceedingJoinPoint;
//import org.aspectj.lang.annotation.Around;
//import org.aspectj.lang.annotation.Aspect;
//import org.aspectj.lang.annotation.Pointcut;
//import org.aspectj.lang.reflect.MethodSignature;
//import org.slf4j.Logger;
//import org.slf4j.LoggerFactory;
//import org.springframework.beans.factory.annotation.Autowired;
//import org.springframework.context.annotation.Configuration;
//import org.springframework.data.redis.core.script.DefaultRedisScript;
//import org.springframework.data.redis.core.script.RedisScript;
//
//import javax.servlet.http.HttpServletRequest;
//import java.lang.reflect.Method;
//
///**
// * aop限流拦截器
// * @author ken
// * @version 1.0
// * @date 2020-09-17
// */
//@Aspect
//@Configuration
//public class LimitAspect {
//
//    private static final Logger logger = LoggerFactory.getLogger(LimitAspect.class);
//
//    private IRedisService redisService;
//
//    @Pointcut("@annotation(com.ccb.sc.common.bind.annotation.Limit)")
//    public void pointcut() {
//
//    }
//
//    @Around("pointcut()")
//    public Object around(ProceedingJoinPoint pjp) throws Throwable {
//        MethodSignature signature = (MethodSignature) pjp.getSignature();
//        Method method = signature.getMethod();
//        Limit limitAnnotation = method.getAnnotation(Limit.class);
//        Limit.LimitType limitType = limitAnnotation.limitType();
//        String key;
//        int limitPeriod = limitAnnotation.period();
//        int limitCount = limitAnnotation.count();
//        HttpServletRequest request = HttpServletRequestUtil.getRequest();
//        String url;
//        String ip;
//        if (request == null) {
//            url = method.getDeclaringClass() + ":" + method.getName();
//            ip = "0";
//        }else {
//            url = request.getRequestURI();
//            ip = IpUtil.getIpAddress(request);
//        }
//        switch (limitType) {
//            case IP:
//                key = ip;
//                break;
//            case CUSTOMER:
//                key = limitAnnotation.key();
//                break;
//            default:
//                key = StringUtils.upperCase(method.getName());
//        }
//
//        // 格式：前缀+url或类加方法名+IP 例 limit:/app/login:127.0.0.1
//        ImmutableList<String> keys = ImmutableList.of(StringUtils.join(CommonRedisKey.LIMIT_REQUEST, url, ":", key));
//
//        String luaScript = buildLuaScript();
//        RedisScript<Long> redisScript = new DefaultRedisScript<>(luaScript, Long.class);
//        Long count = this.redisService.execute(redisScript, keys, limitCount, limitPeriod);
//        //logger.info("Access try count is [{}] for name=[{}] and key = [{}] and ip = [{}]", count, url, key, ip);
//        if (count != null && count <= limitCount) {
//            return pjp.proceed();
//        } else {
//            if(!"0".equals(ip)) {
//                this.redisService.getNextByDayClean(CommonRedisKey.LIMIT_REQUEST + key);
//            }
//            logger.error("请求过于频繁,count={}, limitCount={}, url={}, ip={}", count, limitCount, url, ip);
//            //psl throw new BizException(BizCodeFace.createBizCode(ErrorCode.FAST_FREQUENCY));
//        }
//    }
//
//    /**
//     * 限流 脚本
//     *
//     * @return lua脚本
//     */
//    public String buildLuaScript() {
//        StringBuilder lua = new StringBuilder();
//        lua.append("local c");
//        lua.append("\nc = redis.call('get',KEYS[1])");
//        // 调用不超过最大值，则直接返回
//        lua.append("\nif c and tonumber(c) > tonumber(ARGV[1]) then");
//        lua.append("\nreturn c;");
//        lua.append("\nend");
//        // 执行计算器自加
//        lua.append("\nc = redis.call('incr',KEYS[1])");
//        lua.append("\nif tonumber(c) == 1 then");
//        // 从第一次调用开始限流，设置对应键值的过期
//        lua.append("\nredis.call('expire',KEYS[1],ARGV[2])");
//        lua.append("\nend");
//        lua.append("\nreturn c;");
//        return lua.toString();
//    }
//
//    @Autowired
//    public void setRedisService(IRedisService redisService) {
//        this.redisService = redisService;
//    }
//
//}
